const jwt = require("jsonwebtoken");
const fs = require("fs");
const { v4: uuidv4 } = require("uuid");
const { query, withTransaction } = require("./db");

// 密钥配置
const privateKey = fs.readFileSync("./public/rsa/private.pem");
const publicKey = fs.readFileSync("./public/rsa/public.pem");

// Token 配置
const TOKEN_CONFIG = {
  access: { expiresIn: "2h" }, // 短期Token
  refresh: { expiresIn: "7d" }, // 长期Token
};

/**
 * 生成双 Token (Access + Refresh)
 * @param {object} user - 用户对象 { FUserId, FUsername }
 * @param {string} deviceInfo - 设备信息
 * @returns {Promise<{accessToken: string, refreshToken: string}>}
 */
async function generateTokens(user, deviceInfo = "unknown") {
  const tokenId = uuidv4(); // 使用 uuidv4 生成唯一标识

  try {
    const [accessToken, refreshToken] = await Promise.all([
      _signToken(user, "access", tokenId),
      _signToken(user, "refresh", tokenId),
    ]);

    // 使用事务保存 Token 和登录记录
    await withTransaction(async (conn) => {
      // 1. 使同一用户的其他 Token 失效（强制下线）
      await query(
        `UPDATE t_user_tokens SET FIsRevoked=1 
         WHERE FUserId=? AND FIsRevoked=0`,
        [user.FUserId],
        conn
      );

      // 2. 存储新 Token
      await query(
        `INSERT INTO t_user_tokens 
         (FId, FUserId, FAccessToken, FRefreshToken, FDeviceInfo, FExpiresAt)
         VALUES (?, ?, ?, ?, ?, DATE_ADD(NOW(), INTERVAL 7 DAY))`,
        [tokenId, user.FUserId, accessToken, refreshToken, deviceInfo],
        conn
      );
    });

    return { accessToken, refreshToken, tokenId };
  } catch (err) {
    throw new Error(`生成Token失败: ${err.message}`);
  }
}

/**
 * 签发 Token（内部方法）
 */
function _signToken(user, type, tokenId) {
  return new Promise((resolve, reject) => {
    const payload = {
      userId: user.FUserId,
      tokenId,
      type,
      username: user.FUsername,
      permission: user.FPermission || "user", // 添加默认权限
    };

    jwt.sign(
      payload,
      privateKey,
      {
        algorithm: "RS256",
        expiresIn: TOKEN_CONFIG[type].expiresIn,
      },
      (err, token) => {
        if (err) reject(new Error(`签发${type} Token失败: ${err.message}`));
        else resolve(token);
      }
    );
  });
}

/**
 * 验证 Token
 * @param {string} token
 * @returns {Promise<object>} 解码后的 payload
 */
async function verifyToken(token) {
  try {
    const decoded = await new Promise((resolve, reject) => {
      jwt.verify(
        token,
        publicKey,
        { algorithms: ["RS256"] },
        (err, decoded) => {
          if (err) {
            if (err.name === "TokenExpiredError") {
              const error = new Error("Token已过期");
              error.code = "TOKEN_EXPIRED";
              return reject(error);
            } else {
              const error = new Error("无效的Token");
              error.code = "INVALID_TOKEN";
              return reject(error);
            }
          }
          resolve(decoded);
        }
      );
    });

    const [tokenRecord] = await query(
      `SELECT 1 FROM t_user_tokens 
       WHERE FId=? AND FIsRevoked=0 LIMIT 1`,
      [decoded.tokenId]
    );

    if (!tokenRecord) {
      const error = new Error("Token已被撤销");
      error.code = "TOKEN_REVOKED"; // ✅ 新增此类型
      throw error;
    }

    return decoded;
  } catch (err) {
    // 保留 error.code 用于前端识别
    throw err;
  }
}

/**
 * 使用 Refresh Token 刷新 Access Token
 * @param {string} refreshToken
 * @returns {Promise<{accessToken: string, refreshToken: string}>} 新的token对
 */
async function refreshAccessToken(refreshToken) {
  try {
    const decoded = await verifyToken(refreshToken);

    if (decoded.type !== "refresh") {
      throw new Error("非法的Refresh Token类型");
    }

    // 验证 Refresh Token 是否有效
    const [tokenRecord] = await query(
      `SELECT t.FUserId, u.FUsername 
       FROM t_user_tokens t
       JOIN t_users u ON t.FUserId = u.FUserId
       WHERE t.FId=? AND t.FRefreshToken=? AND t.FIsRevoked=0 LIMIT 1`,
      [decoded.tokenId, refreshToken]
    );

    if (!tokenRecord) {
      throw new Error("Refresh Token无效或已过期");
    }

    // 生成新的Token对
    const user = {
      FUserId: tokenRecord.FUserId,
      FUsername: tokenRecord.FUsername,
      FPermission: tokenRecord.FPermission,
    };
    const {
      accessToken,
      refreshToken: newRefreshToken,
      tokenId,
    } = await generateTokens(user);

    return { accessToken, refreshToken: newRefreshToken, tokenId };
  } catch (err) {
    throw new Error(`刷新Token失败: ${err.message}`);
  }
}

/**
 * 强制下线用户
 * @param {string} userId
 * @param {string} reason
 */
async function forceLogout(userId, reason = "管理员操作") {
  try {
    await withTransaction(async (conn) => {
      // 1. 撤销所有 Token
      await query(
        `UPDATE t_user_tokens SET FIsRevoked=1 WHERE FUserId=?`,
        [userId],
        conn
      );

      // 2. 记录下线日志
      await query(
        `UPDATE t_user_login_history 
         SET FIsForcedLogout=1, FReason=?, FLogoutAt=NOW()
         WHERE FUserId=? AND FLogoutAt IS NULL`,
        [reason, userId],
        conn
      );
    });
    return { success: true, message: "用户已强制下线" };
  } catch (err) {
    throw new Error(`强制下线操作失败: ${err.message}`);
  }
}

module.exports = {
  generateTokens,
  verifyToken,
  refreshAccessToken,
  forceLogout,
};
